from khronos.utils.misc import UNDEF

class Prompt(object):
    def __init__(self, question="Do you wish to continue?", options=("Yes", "No"), 
                 tries=3, fail_value=None, shortcuts=True, 
                 case_sensitive=False, strip_whitespace=True):
        self.tries = tries
        self.fail_value = fail_value
        self.shortcuts = shortcuts
        self.case_sensitive = case_sensitive
        self.strip_whitespace = strip_whitespace
        # Build the prompt line and list of acceptable answers. If shortcuts are used,
        # use the first character in each answer as a shortcut to that answer.
        acceptable = list(options)
        prompt_options = acceptable
        if shortcuts:
            prompt_options = []
            for option in list(acceptable):
                if len(option) > 1 and option[0] not in acceptable:
                    acceptable.append(option[0])
                    option = "[%s]%s" % (option[0], option[1:])
                prompt_options.append(option)
        prompt_line = "".join([question, " (", ", ".join(prompt_options), ") "])
        # Save compiled data into Prompt object.
        self.prompt_line = prompt_line
        self.acceptable_normalcase = set(acceptable)
        self.acceptable_lowercase = set([option.lower() for option in acceptable])
        
    def __call__(self, tries=UNDEF, fail_value=UNDEF, 
                 case_sensitive=UNDEF, strip_whitespace=UNDEF):
        if            tries is UNDEF: tries            = self.tries
        if       fail_value is UNDEF: fail_value       = self.fail_value
        if   case_sensitive is UNDEF: case_sensitive   = self.case_sensitive
        if strip_whitespace is UNDEF: strip_whitespace = self.strip_whitespace
        # Prompt main loop. Ask for an answer until either the maximum number of tries
        # is expired or a valid answer is given.
        options = self.acceptable_normalcase if case_sensitive else self.acceptable_lowercase
        try:
            for attempt in xrange(1, tries + 1):
                answer = raw_input("[%s/%s] " % (attempt, tries) + self.prompt_line)
                if     strip_whitespace: answer = answer.strip()
                if   not case_sensitive: answer = answer.lower()
                if answer in options: return answer
        except KeyboardInterrupt:
            pass
        # If a keyboard interrupt has been caught, or the maximum number of tries is 
        # exceeded, return the specified fail value.
        return fail_value
        
def prompt(*args, **kwargs):
    p = Prompt(*args, **kwargs)
    return p()
    
